home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Code Resources / 3D Buttons CDEF 1.0b4 / Source / 3D Buttons CDEF source / (3D Buttons CDEF.π) / LGBRadio.cp < prev    next >
Encoding:
Text File  |  1994-07-31  |  15.0 KB  |  544 lines  |  [TEXT/MMCC]

  1. /**************************************************************************
  2.     LGBRadio
  3.     
  4.     Public domain, by Zig Zichterman.
  5.     
  6.     This class implements 3D radio buttons according to the guidelines
  7.     suggested in _develop_ 15. Some of the drawing code is taken from
  8.     the public domain source accompanying _develop_ 15.
  9.  
  10.         07/31/94    zz    Draw 3D if 4-bit grey, BW if 4-bit color
  11.         07/31/94    zz    save/restore pen colors
  12.     1.0b3
  13.         07/28/94    zz    add offscreen drawing for less flashy TextBox()
  14.     1.0b2 (never released)
  15.         07/20/94    zz    call PenNormal() before drawing anything!
  16.     1.01b1
  17. **************************************************************************/
  18. #include "LGBRadio.h"
  19.  
  20. #include <GestaltEqu.h>
  21.  
  22. #include "LGBControl.h"
  23. #include "LGBDeviceIterator.h"
  24. #include "UGBDraw.h"
  25.  
  26. /**************************************************************************
  27.     Main()                                                        [static]
  28.     
  29.     Main entry point for all radio button calls. Dispatch according to
  30.     message.
  31. **************************************************************************/
  32. long
  33. LGBRadio::Main(short inVariation, ControlHandle ioControl,
  34.         short inMsg, long ioParam)
  35. {
  36.     long            returnMe    = 0;
  37.  
  38.     // lock the control handle for the duration of this call
  39.     char state = ::HGetState((Handle) ioControl);
  40.     ::HLock((Handle) ioControl);
  41.     
  42.     LGBRadio    radio(*ioControl,(inVariation & useWFont)?true:false);
  43.     
  44.     switch (inMsg) {
  45.         case drawCntl    :
  46.                 radio.Draw(ioParam);
  47.                 break;
  48.                             
  49.         case testCntl    :
  50.             {
  51.                 Point    hitPt;
  52.                 hitPt.h    = LoWord(ioParam);
  53.                 hitPt.v    = HiWord(ioParam);
  54.                 if (radio.Test(hitPt)) {
  55.                     returnMe = inButton;
  56.                 }
  57.             }
  58.             break;
  59.         
  60.         case calcCRgns    :    // only called in 24-bit mode
  61.             {    // is 32-bit addressing off?
  62.                 long    result    = 0;
  63.                 OSErr    err = ::Gestalt(gestaltAddressingModeAttr,&result);
  64.                 if (!err && ((result &
  65.                         (1L << gestalt32BitAddressing)) == 0)) {
  66.                     RgnHandle    rgn = (RgnHandle)
  67.                                     ::StripAddress((Ptr) ioParam);
  68.                     radio.CalcCRgn(rgn);
  69.                 }
  70.             }
  71.             break;
  72.         
  73.         case calcCntlRgn    :    // only called in 32-bit mode
  74.             radio.CalcCRgn((RgnHandle) ioParam);
  75.             break;
  76.     }
  77.     
  78.     // unlock handle
  79.     ::HSetState((Handle) ioControl,state);
  80.     return returnMe;
  81. }
  82.  
  83. //—————————————————————————————————————————————————————————————————————————
  84. // Constructor
  85. //—————————————————————————————————————————————————————————————————————————
  86.  
  87. /**************************************************************************
  88.     LGBRadio(ControlHandle,Boolean)
  89.     
  90.     construct/initialize a control object. Just stores the control handle
  91.     and the "should I use the window font?" flag in data members.
  92. **************************************************************************/
  93. LGBRadio::LGBRadio(ControlRecord *inControl, Boolean inUseWFont)
  94.     : mControl(inControl), mUseWFont(inUseWFont)
  95. {
  96.  
  97. }
  98.  
  99. //—————————————————————————————————————————————————————————————————————————
  100. // Dispatch entry points
  101. //—————————————————————————————————————————————————————————————————————————
  102.  
  103. /**************************************************************************
  104.     Draw()
  105.     
  106.     Draw the control. inPartCode is a part code specifying which part of
  107.     the control to draw, or 0 for the entire control.
  108.     
  109.     Radio buttons only have inButton, so we ignore the inPartCode.
  110.  
  111.     Save the current drawing environment. Iterate through all the devices
  112.     (screens), drawing the control in color or black and white depending
  113.     on the screen depth. Once done, restore the drawing environment and
  114.     return.
  115. **************************************************************************/
  116. void
  117. LGBRadio::Draw(long inPartCode)
  118. {
  119.     // if we're invisible, don't draw
  120.     if (mControl->contrlVis == false) return;
  121.  
  122.     // save the font
  123.     short    font,size,mode,face;
  124.     {
  125.         GrafPtr    port;
  126.         ::GetPort(&port);
  127.         font    = port->txFont;
  128.         size    = port->txSize;
  129.         mode    = port->txMode;
  130.         face    = port->txFace;
  131.     }
  132.  
  133.     // save the pen colors        // will probably crash SEs, so test first
  134.     RGBColor    fore,back;
  135.     if (UGBDraw::ColorQDIsPresent()) {
  136.         ::GetForeColor(&fore);
  137.         ::GetBackColor(&back);
  138.     }
  139.     
  140.     // save the clip region
  141.     RgnHandle    saveClip    = ::NewRgn();
  142.     if (!saveClip) return;
  143.     ::GetClip(saveClip);
  144.     
  145.     // make the pen something sensible
  146.     ::PenNormal();
  147.     ::ForeColor(blackColor);
  148.     ::BackColor(whiteColor);
  149.  
  150.     // loop through all the devices (screens)
  151.     UGBDraw::Offscreen    offscreen;
  152.     LGBDeviceIterator    device;
  153.     device.Init(mControl->contrlRect);
  154.     short    depth    = 0;
  155.     do {
  156.         depth = device.Next();
  157.         if (depth == 0) break;    // all done with devices
  158.         UGBDraw::OffscreenPre(offscreen);
  159.         if ((depth < 4)
  160.                 || (depth == 4 && device.mDeviceIsColor)) {
  161.             DrawBW();
  162.         } else {
  163.             DrawColor();
  164.         }
  165.         UGBDraw::OffscreenPost(offscreen);
  166.     } while(true);
  167.  
  168.     // restore the clip region
  169.     ::SetClip(saveClip);
  170.     ::DisposeRgn(saveClip);
  171.     
  172.     // restore the pen
  173.     if (UGBDraw::ColorQDIsPresent()) {
  174.         ::RGBForeColor(&fore);
  175.         ::RGBBackColor(&back);
  176.     }
  177.  
  178.     // restore the font
  179.     ::TextFont(font);
  180.     ::TextSize(size);
  181.     ::TextMode(mode);
  182.     ::TextFace(face);
  183. }
  184.  
  185. /**************************************************************************
  186.     Test()
  187.     
  188.     Return inButton if the point is in our rect
  189. **************************************************************************/
  190. Boolean
  191. LGBRadio::Test(Point inHitPt)
  192. {
  193.     return ::PtInRect(inHitPt,&(mControl->contrlRect));
  194. }
  195.  
  196. /**************************************************************************
  197.     CalcCRgn()
  198.     
  199.     Calculate the control's region in the given region handle. Just
  200.     return our rect as a region
  201. **************************************************************************/
  202. void
  203. LGBRadio::CalcCRgn(RgnHandle ioRgn)
  204. {
  205.     if (!ioRgn) return;        // idiot resistance
  206.     ::RectRgn(ioRgn,&(mControl->contrlRect));
  207. }
  208.  
  209. //—————————————————————————————————————————————————————————————————————————
  210. // Draw
  211. //—————————————————————————————————————————————————————————————————————————
  212.  
  213. /**************************************************************************
  214.     DrawBW()
  215.     
  216.     Draw the control in 1-bit. Make no color QD calls here.
  217. **************************************************************************/
  218. void
  219. LGBRadio::DrawBW(void)
  220. {
  221.     // Set the pen to black, 1x1
  222.     ::PenNormal();
  223.     
  224.     // set up our font
  225.     if (!mUseWFont) LGBControl::SetupFont();
  226.     
  227.     // calculate box locations
  228.     Rect    radiobox,titleBox;
  229.     CalcBoxes(radiobox,titleBox);
  230.     
  231.     // draw the parts
  232.     DrawRadio(radiobox);
  233.     DrawTitle(titleBox,mControl->contrlHilite == 255);
  234. }
  235.  
  236. /**************************************************************************
  237.     DrawColor()
  238.     
  239.     Draw the control in color, either active or inactive
  240. **************************************************************************/
  241. void
  242. LGBRadio::DrawColor(void)
  243. {
  244.     UGBDraw::PenNormal();
  245.     ::EraseRect(&(mControl->contrlRect));
  246.     
  247.     if (mControl->contrlHilite == 255) {
  248.         DrawColorInactive();
  249.     } else {
  250.         DrawColorActive();
  251.     }
  252.  
  253.     // restore the pen
  254.     ::PenNormal();
  255.     UGBDraw::PenReallyNormal();
  256. }
  257.  
  258. /**************************************************************************
  259.     DrawColorInactive()
  260.     
  261.     Draw the control in color, inactive state.
  262. **************************************************************************/
  263. void
  264. LGBRadio::DrawColorInactive(void)
  265. {
  266.     // set the pen to inactive grey, background to light grey
  267.     UGBDraw::PenFrameInactive();
  268.     UGBDraw::Background();
  269.     
  270.     // set up our font
  271.     if (!mUseWFont) LGBControl::SetupFont();
  272.     
  273.     // calculate box locations
  274.     Rect    radiobox,titleBox;
  275.     CalcBoxes(radiobox,titleBox);
  276.     
  277.     // draw the parts
  278.     DrawRadio(radiobox);
  279.     DrawTitle(titleBox);
  280. }
  281.  
  282. /**************************************************************************
  283.     DrawColorActive()
  284.     
  285.     Draw the control in color, inactive state
  286. **************************************************************************/
  287. void
  288. LGBRadio::DrawColorActive(void)
  289. {
  290.     // set the pen to active black, background to light grey
  291.     UGBDraw::PenFrameActive();
  292.     UGBDraw::Background();
  293.     
  294.     // set up our font
  295.     if (!mUseWFont) LGBControl::SetupFont();
  296.     
  297.     // calculate box locations
  298.     Rect    radiobox,titleBox;
  299.     CalcBoxes(radiobox,titleBox);
  300.     
  301.     // draw the title
  302.     DrawTitle(titleBox);
  303.  
  304.     // draw the radio
  305.     DrawRadioColor(radiobox);
  306. }
  307.  
  308.  
  309. /**************************************************************************
  310.     DrawRadioColor()
  311.     
  312.     Draw the radio button (just the cirular part, not the title)
  313.     in color. This is fairly icky, so it deserves its own function
  314. **************************************************************************/
  315. void
  316. LGBRadio::DrawRadioColor(const Rect &inRadiobox)
  317. {
  318.     if (mControl->contrlHilite) {    // draw flat, shouldn't occur any more
  319.         UGBDraw::Background();
  320.         UGBDraw::PenFrameActive();
  321.         DrawRadio(inRadiobox);
  322.     } else {                        // draw 3D
  323.         // draw the frame
  324.         ::FrameOval(&inRadiobox);
  325.         
  326.         // erase the guts if not tristated
  327.         const short value = mControl->contrlValue;
  328.         if (value <= 1) {            // erase the innerds
  329.             Rect    eraseMe;
  330.             eraseMe.top        = inRadiobox.top + 1;
  331.             eraseMe.left    = inRadiobox.left + 1;
  332.             eraseMe.right    = inRadiobox.right - 1;
  333.             eraseMe.bottom    = inRadiobox.bottom - 1;
  334.             UGBDraw::BackGrey(UGBDraw_greyF);
  335.             ::EraseOval(&eraseMe);
  336.             UGBDraw::Background();
  337.         }
  338.         
  339.         if (value == 0) {            // empty/convex
  340.             Rect    box = inRadiobox;
  341.             
  342.             UGBDraw::ForeGrey(UGBDraw_greyE);
  343.             ::MoveTo(box.left + 6, box.top + 2);
  344.             ::LineTo(box.left + 3, box.top + 5);
  345.             ::MoveTo(box.left + 4, box.top + 5);
  346.             ::LineTo(box.left + 7, box.top + 2);
  347.             ::MoveTo(box.left + 3, box.top + 5);
  348.             ::LineTo(box.left + 3, box.top + 7);
  349.             
  350.             UGBDraw::ForeGrey(UGBDraw_greyD);
  351.             ::MoveTo(box.left + 3, box.top + 8);
  352.             ::LineTo(box.left + 4, box.top + 8);
  353.             ::LineTo(box.left + 4, box.top + 6);
  354.             ::LineTo(box.left + 6, box.top + 6);
  355.             ::LineTo(box.left + 6, box.top + 4);
  356.             ::LineTo(box.left + 7, box.top + 4);
  357.             ::LineTo(box.left + 7, box.top + 3);
  358.             ::LineTo(box.left + 8, box.top + 3);
  359.             ::LineTo(box.left + 8, box.top + 2);
  360.             ::MoveTo(box.left + 5, box.top + 5);
  361.             ::Line(0,0);
  362.             ::MoveTo(box.left + 7, box.top + 5);
  363.             ::Line(0,0);
  364.             ::MoveTo(box.left + 5, box.top + 7);
  365.             ::Line(0,0);
  366.  
  367.             UGBDraw::ForeGrey(UGBDraw_greyB);
  368.             ::MoveTo(box.left + 3, box.top + 9);
  369.             ::LineTo(box.left + 5, box.top + 9);
  370.             ::LineTo(box.left + 5, box.top + 8);
  371.             ::LineTo(box.left + 6, box.top + 8);
  372.             ::LineTo(box.left + 6, box.top + 7);
  373.             ::LineTo(box.left + 7, box.top + 7);
  374.             ::LineTo(box.left + 7, box.top + 6);
  375.             ::LineTo(box.left + 8, box.top + 6);
  376.             ::LineTo(box.left + 8, box.top + 4);
  377.  
  378.             UGBDraw::ForeGrey(UGBDraw_greyA);
  379.             ::MoveTo(box.left + 6, box.top + 9);
  380.             ::LineTo(box.left + 7, box.top + 9);
  381.             ::LineTo(box.left + 7, box.top + 8);
  382.             ::LineTo(box.left + 8, box.top + 8);
  383.             ::LineTo(box.left + 8, box.top + 7);
  384.             ::LineTo(box.left + 9, box.top + 7);
  385.             ::LineTo(box.left + 9, box.top + 2);
  386.  
  387.             UGBDraw::ForeGrey(UGBDraw_grey8);
  388.             ::MoveTo(box.left + 4, box.top + 10);
  389.             ::LineTo(box.left + 7, box.top + 10);
  390.             ::MoveTo(box.left + 8, box.top + 9);
  391.             ::LineTo(box.left + 9, box.top + 9);
  392.             ::LineTo(box.left + 9, box.top + 8);
  393.             ::MoveTo(box.left + 10, box.top + 7);
  394.             ::LineTo(box.left + 10, box.top + 4);
  395.  
  396.         } else if (value == 1) {    // draw with a dot/concave
  397.             Rect    box = inRadiobox;
  398.             
  399.             UGBDraw::ForeGrey(UGBDraw_greyE);
  400.             ::MoveTo(box.left + 9, box.top + 5);
  401.             ::LineTo(box.left + 9, box.top + 7);
  402.             ::MoveTo(box.left + 5, box.top + 9);
  403.             ::LineTo(box.left + 7, box.top + 9);
  404.             
  405.             UGBDraw::ForeGrey(UGBDraw_greyD);
  406.             ::MoveTo(box.left + 3, box.top + 9);
  407.             ::LineTo(box.left + 4, box.top + 9);
  408.             ::MoveTo(box.left + 9, box.top + 3);
  409.             ::LineTo(box.left + 9, box.top + 4);
  410.             
  411.             UGBDraw::ForeGrey(UGBDraw_greyB);
  412.             ::MoveTo(box.left + 2, box.top + 9);
  413.             ::LineTo(box.left + 2, box.top + 8);
  414.             ::LineTo(box.left + 3, box.top + 8);
  415.             ::MoveTo(box.left + 8, box.top + 3);
  416.             ::LineTo(box.left + 8, box.top + 2);
  417.             ::LineTo(box.left + 9, box.top + 2);
  418.  
  419.             UGBDraw::ForeGrey(UGBDraw_greyA);
  420.             ::MoveTo(box.left + 2, box.top + 7);
  421.             ::LineTo(box.left + 2, box.top + 4);
  422.             ::LineTo(box.left + 4, box.top + 2);
  423.             ::LineTo(box.left + 7, box.top + 2);
  424.  
  425.             UGBDraw::ForeGrey(UGBDraw_grey8);
  426.             ::MoveTo(box.left + 1, box.top + 7);
  427.             ::LineTo(box.left + 1, box.top + 4);
  428.             ::LineTo(box.left + 4, box.top + 1);
  429.             ::LineTo(box.left + 7, box.top + 1);
  430.             ::MoveTo(box.left + 2, box.top + 2);
  431.             ::Line(0,0);
  432.  
  433.             // draw •
  434.             UGBDraw::PenFrameActive();
  435.             Rect    x = inRadiobox;
  436.             ::InsetRect(&x,3,3);
  437.             ::PaintOval(&x);
  438.         } else if (value == 2) {                    // tristate
  439.             // fabricate a ltGray pattern on the fly. We don't
  440.             // have quickdraw globals and I'm not going to set
  441.             // up A4 to get them.
  442.             unsigned char ltGrey[8];
  443.             ltGrey[0] = ltGrey[2] = ltGrey[4] = ltGrey[6] = 0x88;
  444.             ltGrey[1] = ltGrey[3] = ltGrey[5] = ltGrey[7] = 0x22;
  445.             
  446.             UGBDraw::ForeGrey(UGBDraw_grey7);
  447.             UGBDraw::BackGrey(UGBDraw_greyD);
  448.  
  449.             Rect    grayRect = inRadiobox;
  450.             ::InsetRect(&grayRect,1,1);
  451.             ::FillOval(&grayRect,(PatPtr) <Grey);
  452.         }
  453.     }
  454. }
  455.  
  456. /**************************************************************************
  457.     CalcBoxes()
  458.     
  459.     Figure out where to draw the checkbox and the title
  460. **************************************************************************/
  461. void
  462. LGBRadio::CalcBoxes(Rect &outRadiobox, Rect &outTitleBox)
  463. {
  464.     const Rect    contrlRect    = mControl->contrlRect;
  465.     const StringPtr    title    = mControl->contrlTitle;
  466.     LGBControl::CalcBoxes(contrlRect,title,
  467.                     outRadiobox,outTitleBox);
  468. }
  469.  
  470. /**************************************************************************
  471.     DrawRadio()
  472.     
  473.     Draw the radio. Draw the "•", everything
  474.     but the title and the background.
  475. **************************************************************************/
  476. void
  477. LGBRadio::DrawRadio(const Rect &inRadiobox)
  478. {
  479.     // draw the frame
  480.     ::FrameOval(&inRadiobox);
  481.     
  482.     // draw the • or erase the guts, if empty or •. No erase if tristated
  483.     const short value = mControl->contrlValue;
  484.     if (value <= 1) {            // erase the innerds
  485.         Rect    eraseMe;
  486.         eraseMe.top        = inRadiobox.top + 1;
  487.         eraseMe.left    = inRadiobox.left + 1;
  488.         eraseMe.right    = inRadiobox.right - 1;
  489.         eraseMe.bottom    = inRadiobox.bottom - 1;
  490.         ::EraseOval(&eraseMe);
  491.     }
  492.     
  493.     if (value == 0) {    // empty. Do nothing (already erased above)
  494.     } else if (value == 1) {    // •
  495.         Rect    x = inRadiobox;
  496.         ::InsetRect(&x,3,3);
  497.         ::PaintOval(&x);
  498.     } else if (value == 2) {                    // tristate
  499.         // fabricate a ltGray pattern on the fly. We don't
  500.         // have quickdraw globals and I'm not going to set
  501.         // up A4 to get them.
  502.         unsigned char ltGrey[8];
  503.         ltGrey[0] = ltGrey[2] = ltGrey[4] = ltGrey[6] = 0x88;
  504.         ltGrey[1] = ltGrey[3] = ltGrey[5] = ltGrey[7] = 0x22;
  505.         
  506.         Rect    grayRect = inRadiobox;
  507.         ::InsetRect(&grayRect,1,1);
  508.         ::FillOval(&grayRect,(PatPtr) <Grey);
  509.     }
  510.     
  511.     // draw highlight
  512.     if ((mControl->contrlHilite)
  513.             && (mControl->contrlHilite != 255)) {
  514.         ::PenNormal();
  515.         Rect    hilite = inRadiobox;
  516.         ::InsetRect(&hilite,1,1);
  517.         ::FrameOval(&hilite);
  518.     }
  519. }
  520.  
  521. /**************************************************************************
  522.     DrawTitle()
  523.     
  524.     Draw the title.
  525. **************************************************************************/
  526. void
  527. LGBRadio::DrawTitle(const Rect &inTitleBox, Boolean inDim1Bit)
  528. {
  529.     const StringPtr    title = mControl->contrlTitle;
  530.     ::TextBox(title + 1,*title,&inTitleBox,teFlushDefault);
  531.  
  532.     // grey out the name if inactive and B&W
  533.     if (inDim1Bit) {
  534.         unsigned char grey[8];
  535.         grey[0] = grey[2] = grey[4] = grey[6] = 0xAA;
  536.         grey[1] = grey[3] = grey[5] = grey[7] = 0x55;
  537.         ::PenPat((PatPtr) grey);
  538.         ::PenMode(patBic);
  539.         ::PaintRect(&inTitleBox);
  540.         ::PenNormal();
  541.     }
  542. }
  543.  
  544.